﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;

namespace jacSocket
{
    class crossDomain
    {
        private readonly string _policyRequestString = "<policy-file-request/>";

        private Socket _listener; 
        private byte[] _policyBuffer; 
        private byte[] _requestBuffer; 

        private int _received; 

        private bool _flag = false; 

        public crossDomain()
        {
            _flag = true;
        }

        internal void StartupPolicyServer()
        {
            string policyFile = Path.Combine(Application.StartupPath, "clientaccesspolicy.xml");

            using (FileStream fs = new FileStream(policyFile, FileMode.Open, FileAccess.Read))
            {
                _policyBuffer = new byte[fs.Length];
                fs.Read(_policyBuffer, 0, _policyBuffer.Length);
            }

            _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _listener.Bind(new IPEndPoint(IPAddress.Any, 943)); 
            _listener.Listen(100);

            _listener.BeginAccept(new AsyncCallback(OnClientConnect), null);
        }

        private void OnClientConnect(IAsyncResult result)
        {
            if (!_flag)
            {
                _listener.BeginAccept(new AsyncCallback(OnClientConnect), null);
                return;
            }

            Socket client; 

            try
            {
                client = _listener.EndAccept(result);
            }
            catch (SocketException)
            {
                return;
            }

            _requestBuffer = new byte[_policyRequestString.Length];
            _received = 0;

            try
            {
                client.BeginReceive(_requestBuffer, 0, _policyRequestString.Length, SocketFlags.None, new AsyncCallback(OnReceive), client);
            }
            catch (SocketException)
            {
                client.Close();
            }

            _listener.BeginAccept(new AsyncCallback(OnClientConnect), null);
        }


        private void OnReceive(IAsyncResult result)
        {
            Socket client = result.AsyncState as Socket;

            try
            {
                _received += client.EndReceive(result);

                if (_received < _policyRequestString.Length)
                {
                    client.BeginReceive(_requestBuffer, _received, _policyRequestString.Length - _received, SocketFlags.None, new AsyncCallback(OnReceive), client);
                    return;
                }

                string request = System.Text.Encoding.UTF8.GetString(_requestBuffer, 0, _received);

                if (StringComparer.InvariantCultureIgnoreCase.Compare(request, _policyRequestString) != 0)
                {
                    client.Close();
                    return;
                }

                client.BeginSend(_policyBuffer, 0, _policyBuffer.Length, SocketFlags.None, new AsyncCallback(OnSend), client);
            }

            catch (SocketException)
            {
                client.Close();
            }
        }

        private void OnSend(IAsyncResult result)
        {
            Socket client = result.AsyncState as Socket;

            try
            {
                client.EndSend(result);
            }
            finally
            {
                client.Close();
            }
        }

        void ResultCallback(object result)
        {

        }
    }
}
